﻿using Serilog;
using System;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace WpfApp1
{
    public class ExceptionHandler
    {
        private readonly ILogger _logger;

        /// <summary>
        /// Sets up unhandled exception listeners and logging for such
        ///
        /// You must call SetupExceptionHandlingEvents() to set up listeners
        /// </summary>
        public ExceptionHandler(ILogger logger)
        {
            _logger = logger;
        }
        /// </summary>
        public bool SetupExceptionHandlingEvents(System.Windows.Application application)
        {
            _logger.Debug("Setting up exception handling");

            //捕获程序中未处理的异常（UI线程）
            application.DispatcherUnhandledException += async (e, x) => await App_DispatcherUnhandledException(e,x);
            //Task线程内未捕获异常处理事件
            TaskScheduler.UnobservedTaskException += async (e, x) => await TaskScheduler_UnobservedTaskException(e, x);
            //捕获Winform程序的未处理异常
            System.Windows.Forms.Application.ThreadException += async (e, x) => await this.Application_ThreadException(e, x);
            // 捕获程序中未处理的异常（非UI线程异常）
            AppDomain.CurrentDomain.UnhandledException += async (e, x) => await CurrentDomainUnhandledException(e, x);
            
            _logger.Debug("Exception handling was set up successfully");
            return true;
        }

        /// <summary>
        /// 捕获Task未处理异常
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="ex"></param>
        private async Task TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
        {
            var exception = e.Exception as Exception;
            await LogException(exception ?? new Exception(), "TaskScheduler.UnobservedTaskException");
        }

        /// <summary>
        /// 捕获Winform程序的未处理异常
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e
        /// "></param>
        private async Task Application_ThreadException(object sender, ThreadExceptionEventArgs e)
        {
            var exception = e.Exception as Exception;
            await LogException(exception ?? new Exception(), "System.Windows.Forms.Application.ThreadException");
        }

        /// <summary>
        /// 主线程异常
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="ex"></param>
        private async Task App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
        {
            var exception = e.Exception as Exception; 
            await LogException(exception ?? new Exception(), "Application.Current.DispatcherUnhandledException");
        }
        /// <summary>
        /// 捕获程序中未处理的异常（非UI线程异常）
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <returns></returns>
        private async Task CurrentDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            var exception = e.ExceptionObject as Exception; 
            await LogException(exception ?? new Exception(), "Application.Current.UnhandledException");
        }

        private async Task LogException(Exception exception, string source)
        {
            var message = $"exception ({source})";
            try
            {
                var assemblyName = System.Reflection.Assembly.GetExecutingAssembly().GetName();
                message = $"exception in {assemblyName.Name} v{assemblyName.Version}";
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "Exception in LogException");
            }
            finally
            {
                await Task.Delay(1000);
                _logger.Error(exception, message);
                Log.CloseAndFlush();
                await Task.Delay(1000);
                Environment.Exit(0);
            }
        }
    }
}
